﻿package com.janisRadins.asDraw {
	import com.robertpenner.bezier.CubicCurve;
	import flash.display.GraphicsPath;
	import flash.geom.Point;
	import mx.utils.ObjectUtil;
	/**
	 * @author Jānis Radiņš
	 */
	public class DrawUtils {
		/**
		 * Static method for joining several GraphicsPath objects into one
		 * @param	... paths	Array of GraphicsPath instances to be joined
		 * @return	new GraphicsPath instance which holds combination of data
		 */
		public static function joinGraphicPaths( ... paths):GraphicsPath {
			if (paths.length == 0) {
				return null;
			}
			var combined:GraphicsPath = new GraphicsPath();
			combined.commands = new Vector.<int>();
			combined.data = new Vector.<Number>();
			var path:GraphicsPath;
			for (var i:uint = 0; i < paths.length; i++) {
				path = paths[i] as GraphicsPath;
				combined.commands = combined.commands.concat(path.commands);
				combined.data = combined.data.concat(path.data);
			}
			return combined;
		}
		/**
		 * Static method that moves GraphicsPath data for certain x and y distance
		 * @param	path	GraphicsPath instance thats should be modified
		 * @param	add		Point which keeps for how much GraphicsPath values should be shifted
		 * @return	GraphicsPath instance
		 */
		public static function moveGraphicPath(path:GraphicsPath, add:Point):GraphicsPath {
			for (var i:uint = 0; i < path.data.length; i++) {
				if (i % 2 == 0) {
					path.data[i] += add.x;
				} else {
					path.data[i] += add.y;
				}
			}
			return path;
		}
		
		public static function svgToPath(svg:XML):Path {
			var data:Array = svg.@d.toString().replace(/( )(M|C|L)/gi, "\n$2").split("\n");
			var path:Path = new Path();
			if (data.length == 0) {
				trace("No path data found");
				return null;
			} 
			var absolutePos:Point = new Point();
			var relativePos:Point = new Point();
			
			var commandStr:String;
			var commandData:Array;
			
			var cubitDrawer:CubicCurve = new CubicCurve();
			var isLocal:Boolean;
			
			main:for (var i:uint = 0; i < data.length; i++) {
				commandStr = String(data[i]).charAt(0);
				commandData = data[i].substr(2).split(" ");
				isLocal = (commandStr.toLocaleLowerCase() === commandStr);
				for (var j:uint = 0; j < commandData.length; j++) {
					commandData[j] = commandData[j].split(",");
					if (!isLocal) {
						commandData[j][0] -= absolutePos.x;
						commandData[j][1] -= absolutePos.y;
					}
				}
				commandStr = commandStr.toLocaleLowerCase();
				relativePos.x = 0;
				relativePos.y = 0;
				switch(commandStr.toLocaleLowerCase()) {
					case "m" :
						absolutePos.x = commandData[0][0];
						absolutePos.y = commandData[0][1];
					
						path.x = absolutePos.x;
						path.y = absolutePos.y;
						break;
					case "c" :
						var curves:Array = cubitDrawer.drawBezier(0, 0, commandData[0][0], commandData[0][1], commandData[1][0], commandData[1][1], commandData[2][0], commandData[2][1]);
						for (var ci:uint = 0; ci < curves.length; ci++) {
							path.curveTo(curves[ci][0], curves[ci][1], curves[ci][2], curves[ci][3]);
							relativePos.x += curves[ci][2];
							relativePos.y += curves[ci][3];
						}
						break;
					case "l" :
						relativePos.x = commandData[0][0];
						relativePos.y = commandData[0][1];
						path.lineTo(relativePos.x, relativePos.y);
						break;
					default :
						trace("Unsupported command: " + data[i]);
						continue main;
				}
				absolutePos = absolutePos.add(relativePos);
			}
			return path;
		}
		
		public static function getPointOnCubitBezzier(t:Number, p0:Number, p1:Number, p2:Number, p3:Number):Number {
			return Math.pow(1 - t, 3) * p0 + 3 * Math.pow(1 - t, 2) * t * p1 + 3 * (1 - t) * Math.pow(t, 2) * p2 + Math.pow(t, 3) * p3;
		}
	}
}